const fs = require("fs").promises;
const { to, haveChinaStr, wait } = require("./utils");
const { translate } = require("./translation");
const { axiosPath, filterInterfaceArr } = require("./config");

async function generatorApiTsFile(tags, paths, docName) {
  // 遍历tags 一个tag一个大模块
  for (let tag of tags) {
    await handleTag(tag, paths, docName);
  }
}

// 一个tag一个大模块
async function handleTag(tag, paths, docName) {
  // 要引入的interface
  let importInterfaceArr = [];
  // 要引入的axios 包装interface
  let importAxiosWrapArr = [];
  const { name } = tag;
  const [err, enName] = await translate(name);
  // 翻译没充钱 免费版限制1秒请求一次
  await wait(1.2);
  console.log("enName", enName);
  let englishName = "";
  try {
    englishName = enName
      .split(" ")
      .map((str) => str.charAt(0).toUpperCase() + str.slice(1))
      .join("");
  } catch (e) {
    console.log("改名报错", e);
  }

  // console.log("tag", tag);
  // 找到paths中所有相同tag的path
  const pathNameArr = Object.keys(paths).filter((pathName) => {
    const tagName = getApiObj(paths, pathName).tags[0];
    // console.log("tagName===name", tagName, name);
    return tagName === name;
  });
  // console.log(`pathNameArr`, pathNameArr);
  // =========================【遍历生成每个api方法】========================
  let tagFileResult = `// ${name}:${englishName} \n${axiosPath}\n`;
  const allApiContent = pathNameArr
    .map((pathName) => {
      const pathMethod = getApiMethod(paths, pathName);
      // console.log({ pathMethod });
      const pathObj = getApiObj(paths, pathName);
      // console.log({ pathObj });

      const interfaceName = (
        pathObj.operationId.charAt(0).toUpperCase() +
        pathObj.operationId.slice(1)
      )
        .split("POST")[0]
        .split("DELETE")[0]
        .split("GET")[0]
        .split("PUT")[0];
      // 参数声明
      const paramsAnnotation = getParamsAnnotation(pathObj);
      // 得到api参数
      const apiReq = getApiReq(pathObj, importInterfaceArr, importAxiosWrapArr);
      // api回调
      const apiRes = getApiRes(pathObj, importInterfaceArr, importAxiosWrapArr);
      // 得到调用axios的参数 需要加上逗号
      const callAxios = getParamsOfCallAxios(pathObj, pathMethod, pathName);

      // ===================【【单个api方法】】=============
      const oneApiMethod = `\n/**
 * summary:${pathObj.summary}
 * description:${pathObj.description}${paramsAnnotation ? paramsAnnotation : ""}
 * */
export const $${interfaceName}=(${apiReq}):${apiRes} => ${callAxios}\n`;
      console.log("单个interface");
      return oneApiMethod;
    })
    .join("");
  // 顶部要引入的interface
  if (importInterfaceArr.length > 0) {
    tagFileResult += `import { ${importInterfaceArr
      .map((interfaceName) => {
        return `${interfaceName}`;
      })
      .join(", ")} } from './interface' \n`;
  }
  // 顶部要引入的axios wrap interface
  if (importAxiosWrapArr.length > 0) {
    tagFileResult += `import { ${importAxiosWrapArr
      .map((interfaceName) => {
        return `${interfaceName}`;
      })
      .join(", ")} } from '@/model/common/global' \n`;
  }
  tagFileResult += allApiContent;
  console.log(`tagFileResult`, tagFileResult);
  const fileName = `./${docName}/${englishName}.ts`;
  to(fs.writeFile(fileName, tagFileResult));
}

/**
 * 得到path的方法 得到 get put post
 * @param {*} paths
 * @param {*} pathName
 * @returns
 */
function getApiMethod(paths, pathName) {
  const result = Object.keys(paths[pathName])[0];
  return result;
}

/**
 * 得到pathItem下方法的内容
 * @param {*} paths
 * @param {*} pathName
 * @returns
 */
function getApiObj(paths, pathName) {
  const result = paths[pathName][getApiMethod(paths, pathName)];
  return result;
}

/**
 * 得到参数声明
 * @param {*} pathObj
 * @returns
 */
function getParamsAnnotation(pathObj) {
  return pathObj.parameters
    ?.map((paramObj) => {
      const content = Object.keys(paramObj)
        .map((paramKey) => {
          const value =
            typeof paramObj[paramKey] === "object"
              ? JSON.stringify(paramObj[paramKey])
              : paramObj[paramKey];
          return ` ${paramKey}:[${value}] `;
        })
        .join(" ");
      return `\n * @param ${paramObj.name} ${content}`;
    })
    .join(" ");
}
// 解析ref TODO:res类型错误 没有MesApiRes包裹起来（后端文档编写问题？）
function resolve$Ref($ref, importInterfaceArr, importAxiosWrapArr) {
  if (!$ref) return "unknown";
  let interface = $ref.includes("«")
    ? $ref.split("«")[1].split("»")[0]
    : $ref.split("schemas/")[1];
  addArr(importInterfaceArr, interface);

  if ($ref === "#/components/schemas/BaseResponse") {
    addArr(importAxiosWrapArr, "MesApiRes");
    return `MesApiRes<never>`;
  } else if ($ref.includes(`IPage`)) {
    addArr(importAxiosWrapArr, "IPage");
    return `IPage<${interface}>`;
  } else if ($ref.includes(`PageRequest`)) {
    addArr(importAxiosWrapArr, "PageRequest");
    return `PageRequest<${interface}>`;
  } else {
    return interface;
  }
}

// 解析表 得出类型
function resolveSchema(schema, importInterfaceArr, importAxiosWrapArr) {
  if (!schema) return "unknown";

  const { type, $ref } = schema;
  if (type) {
    if (type === "string") return "string";
    if (type === "integer") return "number";
    if (type === "array") {
      return `${resolve$Ref(
        schema.items.$ref,
        importInterfaceArr,
        importAxiosWrapArr
      )}[]`;
    }
  } else if ($ref) {
    console.log("复杂类型", $ref);
    return resolve$Ref($ref, importInterfaceArr, importAxiosWrapArr);
  }
}

/**
 * 得到api路径
 * @param {*} params
 */
function getApiPath(pathName) {
  // '/apimes${path 如果path中有括号，则增加$前缀 }${遍历querys得出querys}',${如果有requestBody则加data固定string}
  return pathName.replace(/{/g, "${");
}

/**
 * 得到调用api方法需要的【函数参数】
 * @param {*} params
 */
function getApiReq(pathObj, importInterfaceArr, importAxiosWrapArr) {
  // ${遍历parameters数组，得到querys和paths的值}, ${有requstBody就传个data,类型为schema即interface.ts里的值，如果是type:{string},则赋值type:{string}}
  const { parameters, requestBody } = pathObj;
  let result = "";
  if (parameters) {
    const parametersReq = parameters
      .map((param) => {
        // console.log(`param`, param);
        const name = param.name;
        const type = resolveSchema(
          param.schema,
          importInterfaceArr,
          importAxiosWrapArr
        );
        return `${name}: ${type}`;
      })
      .join(", ");
    result += parametersReq;
  }
  if (requestBody) {
    const type = resolveSchema(
      requestBody.content[`application/json`].schema,
      importInterfaceArr,
      importAxiosWrapArr
    );
    console.log("body", requestBody.content[`application/json`].schema);
    result === "" ? (result = `data: ${type}`) : (result += `, data: ${type}`);
  }
  return result;
}

/**
 * 得到api回调
 * @param {*} params
 */
function getApiRes(pathObj, importInterfaceArr, importAxiosWrapArr) {
  //pathObj.responses[200].content['*/*'].schema.$ref 如何根据 #/components/schemas/BaseResponse 得到interface的具体值？
  // console.log("getApiRes pathObj", pathObj);
  const type = resolveSchema(
    pathObj.responses[200]?.content?.["*/*"]?.schema,
    importInterfaceArr,
    importAxiosWrapArr
  );
  return ` Promise<${type}> `;
}

// 去重引入interface数组
function addArr(arr, str) {
  const includes = arr.includes(str);
  const skip = filterInterfaceArr.includes(str);
  !skip && !includes && arr.push(str);
}

/**
 * 得到调用axios的【接口参数】
 * axios真实path,请求路径
 * query 和 params 和 data参数都在这里
 * @param {*} params
 */
function getParamsOfCallAxios(pathObj, pathMethod, pathName) {
  // 得到api路径
  let apiPath = getApiPath(pathName);

  const parameters = pathObj.parameters;
  const requestBody = pathObj.requestBody;
  console.log("pathMethod", pathMethod);
  console.log("apiPath", apiPath, pathObj);
  let paramsStr = "";
  if (requestBody) paramsStr += `, data`;
  if (!parameters) return `$axios.${pathMethod}(\`${apiPath}\`${paramsStr})`;
  const queryArr = [];
  // 处理出query params body
  for (let param of parameters) {
    if (!param) continue;
    if (param.in === "query") {
      queryArr.push(param.name);
    } else if (param.in.includes("body") && paramsStr !== `, data`) {
      // TODO: put post有data不会执行这行代码
      paramsStr += `, data`;
    } else if (param.in === "path") {
    } else {
    }
    // switch (pathMethod) {
    //   case "get":
    //     break;
    //   case "put":
    //     break;
    //   case "post":
    //     break;
    //   default:
    //     break;
    // }
  }
  // 请求路径中的查询字符串
  if (queryArr.length !== 0) {
    apiPath += "?";
    apiPath += queryArr
      .map((queryKey) => `${queryKey}=\$\{${queryKey}\}`)
      .join("&");
  }
  return `$axios.${pathMethod}(\`${apiPath}\`${paramsStr})`;
}

//  ergodicTags() 遍历tags 一个tag一个interface文件 一个axios文件
//  findAllTagsPaths(tags) 在tags里遍历paths，判断tags数组第一项 与 tag是否相同 相同加入数组
//  得出tags的数组
// tag
//  ergodicPaths(obj) 遍历tags下的所有paths
//  handlePathItem(key) 处理path
//  getApiMethod(value)
//  item=value[method]
//  itemType
//  handleParams 处理parameters 遍历parameters数组 param
//  const interfaceName=pathObj.operationId.charAt(0).toUpperCase() +pathObj.operationId.slice(1);
//  paramsAnnotation=pathObj.parameters.map(param=>{ return `@param name:${param.name} in:${param.in} desceiption:${param.description} \n`  })

//  interfaceParam=
//  interfaceRes=
// result=''
// // 没必要使用prefix
// result+= `

//  /**
//   * summary:${pathObj.summary}
//   * description:${pathObj.description}
//   *  ${paramsAnnotation}
//   *
//   * /
// export type ${interfaceName}Res=${path[method].responses[200].content['*/*'].schema.$ref 如何根据 #/components/schemas/BaseResponse 得到interface的具体值？}
//  export const $${pathObj.operationId}=(${遍历parameters数组，得到querys和paths的值}, ${有requstBody就传个data,类型为schema即interface.ts里的值，如果是type:{string},则赋值type:{string}}):Promise<MesApiRes<${interfaceName}Res>> => $axios.${method}('/apimes${path 如果path中有括号，则增加$前缀 }${遍历querys得出querys}',${如果有requestBody则加data固定string})

module.exports = {
  generatorApiTsFile,
};
